
package cn.edu.neu.oasis;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * @author Oasis
 * 
 */
public class ManagerImpl extends UnicastRemoteObject implements Manager {
	
	/**
	 * 
	 */
	private static final long		serialVersionUID	= -2970402881653724001L;
	
	private HashMap<String, User>	userList;
	
	public static long				id					= 1;
	
	@SuppressWarnings("unchecked")
	public ManagerImpl() throws RemoteException {
	
		super();
		try {
			ObjectInputStream ois =
					new ObjectInputStream(new FileInputStream("user.dat"));
			
			userList = (HashMap<String, ManagerImpl.User>) ois.readObject();
			ois.close();
		} catch (FileNotFoundException e) {
			userList = new HashMap<String, User>();
		} catch (IOException e) {
			userList = new HashMap<String, User>();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			userList = new HashMap<String, User>();
		}
	}
	
	class Meeting implements Serializable {
		
		private static final long	serialVersionUID	= -8513612675071943144L;
		
		long						startTime;
		
		long						endTime;
		
		String						title;
		
		long						mid;
		
		String						starter				= null;
		
		String						anotheruser			= null;
		
		/**
		 * @param startTime
		 * @param endTime
		 * @param title
		 * @param mid
		 *            use startTime,endTime, title and mid to construct a new
		 *            meeting
		 */
		public Meeting(long startTime, long endTime, String title, long mid,
				String user, String anotheruser) {
		
			this.startTime = startTime;
			this.endTime = endTime;
			this.title = title;
			this.mid = mid;
			this.starter = user;
			this.anotheruser = anotheruser;
		}
		
		/**
		 * @return the id of the meeting
		 */
		public long getMid() {
		
			return mid;
		}
		
		/**
		 * @see java.lang.Object#toString()
		 *      return the details of the meeting
		 */
		@Override
		public String toString() {
		
			return "Meeting \t[title=" + title + ", mid=" + mid
					+ "\r\n\tstartTime=" + startTime + ", endTime=" + endTime
					+ "\r\n\tstarter=" + starter + ", anotheruser="
					+ anotheruser + "]\r\n\r\n";
		}
		
		/**
		 * @return the user name of the starter
		 */
		public String getStarter() {
		
			return starter;
		}
		
		/**
		 * @return the user being invited in the meeting
		 */
		public String getAnotheruser() {
		
			return anotheruser;
		}
		
	}
	
	class User implements Serializable {
		
		/**
		 * 
		 */
		private static final long	serialVersionUID	= -2874598107342276826L;
		
		private String				username;
		
		private String				passwd;
		
		private ManagerImpl			manager;
		
		public ArrayList<Meeting>	meetList			=
																new ArrayList<Meeting>();
		
		public User(String username, String passwd, ManagerImpl m) {
		
			this.manager = m;
			this.username = username;
			this.passwd = passwd;
		}
		
		public boolean free(long s, long e) {
		
			for (Meeting m : meetList)
				if (!(m.endTime < s || m.startTime > e)) {
					return false;
				}
			return true;
		}
		
		public void delete(Meeting m) {
		
			this.meetList.remove(m);
			if (this.username.equals(m.starter))
				this.manager.getUser(m.anotheruser).meetList.remove(m);
			else
				this.manager.getUser(m.starter).meetList.remove(m);
		}
	}
	
	public boolean save() {
	
		try {
			File file = new File("user.dat");
			ObjectOutputStream oos =
					new ObjectOutputStream(new FileOutputStream(file));
			oos.writeObject(userList);
			oos.close();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}
	
	public User getUser(String username) {
	
		return userList.get(username);
	}
	
	@Override
	public String register(String username, String passwd) {
	
		if (userList.get(username) != null)
			return "Username Has Been Taken, Please Change Your Username";
		else if (username.equals(""))
			return "Please Input Your Username";
		else if (passwd.equals(""))
			return "Please Input Your Password";
		else {
			
			userList.put(username, new User(username, passwd, this));
			this.save();
			return "Congradulations!Register Successfully!" + username;
		}
	}
	
	@Override
	public String add(String username, String passwd, String anotherUser,
			long startTime, long endTime, String title) {
	
		User user = userList.get(username);
		if (user == null || !user.passwd.equals(passwd))
			return "Wrong User Information,Please Check";
		else {
			User anotheruser = userList.get(anotherUser);
			if (anotheruser == null)
				return "The User You Invite Doesnot Exist";
			else if (startTime >= endTime)
				return "Start Time Must Be Earlier Than End Time";
			else if (user.free(startTime, endTime)
					&& anotheruser.free(startTime, endTime)) {
				Meeting m =
						new Meeting(startTime, endTime, title, id, username,
								anotherUser);
				user.meetList.add(m);
				anotheruser.meetList.add(m);
				id++;
				this.save();
				return "Succeed in Adding Meeting\r\n Please Remember The Meeting ID:"
						+ (id - 1);
			} else if (!user.free(startTime, endTime)) {
				return "There Is Already A Meeting At Given Time";
			} else if (!anotheruser.free(startTime, endTime)) {
				return "The User You Invite Will Be Having A Meeting At Given Time";
			} else {
				return "Both You And The User You Invite Will Be Busy At Given Time";
			}
		}
		
	}
	
	@Override
	public String query(String username, String passwd, long startTime,
			long endTime) {
	
		User u = userList.get(username);
		if (u == null || !u.passwd.equals(passwd))
			return "Wrong User Information,Please Check";
		else if (u.meetList.isEmpty())
			return "You Meeting List Is Empty";
		else if (startTime >= endTime)
			return "Start Time Must Be Earlier Than End Time";
		else {
			
			String str = "";
			for (Meeting m : u.meetList) {
				
				long startDate =
						Long.parseLong((m.startTime + "").substring(0, 8));
				if (startDate >= startTime && startDate <= endTime) {
					str = str + m + "\r\n";
				}
			}
			return str;
		}
	}
	
	@Override
	public String delete(String username, String passwd, long mid) {
	
		User u = userList.get(username);
		if (u == null || !u.passwd.equals(passwd))
			return "Wrong User Information,Please Check";
		else if (u.meetList.isEmpty())
			return "Your Meeting List Is Empty";
		else {
			
			for (Meeting m : u.meetList)
				if (m.mid == mid) {
					u.delete(m);
					this.save();
					return "Delete The Given Meeting Successfully";
				}
			return "Cannot Find The Meeting With Given ID";
		}
	}
	
	@Override
	public String clear(String username, String passwd) {
	
		User u = userList.get(username);
		if (u == null || !u.passwd.equals(passwd))
			return "Wrong User Information,Please Check";
		else {
			for (Meeting m : u.meetList) {
				u.delete(m);
			}
			this.save();
			return "All Meetings Have Been Deleted";
		}
	}
	
	@Override
	public boolean login(String username, String password) {
	
		if (userList.get(username) != null
				&& userList.get(username).passwd.equals(password))
			return true;
		else
			return false;
	}
}
